package pl.edu.agh.neuraleconomy.ui.chart.provider;

import java.util.Date;
import java.util.List;
import java.util.Map;

import pl.edu.agh.neuraleconomy.core.nn.NeuralNetworkService;
import pl.edu.agh.neuraleconomy.core.nn.CoreUtils;
import pl.edu.agh.neuraleconomy.core.nn.SimpleNetwork;
import pl.edu.agh.neuraleconomy.core.nn.transformer.IDataTransformer;
import pl.edu.agh.neuraleconomy.core.ta.indicator.ICalculator;
import pl.edu.agh.neuraleconomy.model.exchange.Exchange;
import pl.edu.agh.neuraleconomy.persistence.base.DaoProvider;
import pl.edu.agh.neuraleconomy.persistence.exchange.ExchangeDao;
import pl.edu.agh.neuraleconomy.ui.chart.PredictionSerieBean;
import pl.edu.agh.neuraleconomy.ui.chart.SerieBean;
import pl.edu.agh.neuraleconomy.ui.types.PredictionDataComposite;

public abstract class AbstractSerieProvider<CALCULATOR extends ICalculator> implements ISerieProvider {

	private ICalculator calculator;
	private NeuralNetworkService neuralService = new NeuralNetworkService();

	public AbstractSerieProvider(ICalculator calculator) {
		this.calculator = calculator;
	}

	public SerieBean getSerie(List<Exchange> data) {
		SerieBean bean = new SerieBean();
		Map<Date, Double> values = calculator.calculate(data);
		for (Exchange e : data) {
			bean.addValue(e.getDate(), values.get(e.getDate()));
		}
		if (!data.isEmpty()) {
			bean.setSerieName(getSerieName(data.get(0)));
		}
		return bean;
	}

	public PredictionSerieBean getPrediction(PredictionDataComposite predictionData) {
		SimpleNetwork network = new SimpleNetwork(predictionData.getNetworkStructure());
		double [] trainData = getTrainData(predictionData.getCompanyId(), predictionData.getDateFrom());
		neuralService.trainNetworkWithData(network, trainData, predictionData.getDataTransformer());
		double[] inputData = getPredictionInputData(network, predictionData.getCompanyId(), predictionData.getDateFrom(), predictionData.getDataTransformer());
		double[] predictedData = neuralService.predictForCompany(network, inputData, predictionData.getSessions(),
				predictionData.getDataTransformer(), true);
		return new PredictionSerieBean(predictionData.getDateFrom(), predictedData);
	}

	protected double[] getTrainData(Long companyId, Date dateFrom) {
		List<Exchange> exchanges = neuralService.getTrainData(companyId, dateFrom);
		return calculator.calculate(CoreUtils.toDoubleArray(exchanges));
	}

	protected double[] getPredictionInputData(SimpleNetwork network, Long companyId, Date dateFrom, IDataTransformer transformer) {
		ExchangeDao dao = DaoProvider.getExchangeDao();

		List<Exchange> exchanges = dao.getLatestByCompanyExcludeDate(companyId, dateFrom,
				(long) calculator.getInputLenForOutputLen(transformer.getInputLenForOutputLen(network.getInput())));
		double data[] = CoreUtils.toDoubleArray(exchanges);

		return calculator.calculate(data);
	}

	protected abstract String getSerieName(Exchange exchcange);

}
